package query

import (
	"context"
	"fmt"
	"github.com/MQEnergy/go-skeleton/internal/app/model"
	"github.com/MQEnergy/go-skeleton/internal/vars"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/log"
	"gorm.io/gen"
	"gorm.io/gen/field"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/schema"
	"strconv"
)

type IDo interface {
	gen.SubQuery
	Debug() IUsersDo
	WithContext(ctx context.Context) IUsersDo
	WithResult(fc func(tx gen.Dao)) gen.ResultInfo
	ReplaceDB(db *gorm.DB)
	ReadDB() IUsersDo
	WriteDB() IUsersDo
	//As(alias string) gen.Dao
	Session(config *gorm.Session) IUsersDo
	Columns(cols ...field.Expr) gen.Columns
	Clauses(conds ...clause.Expression) IUsersDo
	Not(conds ...gen.Condition) IUsersDo
	Or(conds ...gen.Condition) IUsersDo
	Select(conds ...field.Expr) IUsersDo
	Where(conds ...gen.Condition) IUsersDo
	Order(conds ...field.Expr) IUsersDo
	Distinct(cols ...field.Expr) IUsersDo
	Omit(cols ...field.Expr) IUsersDo
	Join(table schema.Tabler, on ...field.Expr) IUsersDo
	LeftJoin(table schema.Tabler, on ...field.Expr) IUsersDo
	RightJoin(table schema.Tabler, on ...field.Expr) IUsersDo
	Group(cols ...field.Expr) IUsersDo
	Having(conds ...gen.Condition) IUsersDo
	Limit(limit int) IUsersDo
	Offset(offset int) IUsersDo
	Count() (count int64, err error)
	Scopes(funcs ...func(gen.Dao) gen.Dao) IUsersDo
	Unscoped() IUsersDo
	Create(values ...*model.Users) error
	CreateInBatches(values []*model.Users, batchSize int) error
	Save(values ...*model.Users) error
	First() (*model.Users, error)
	Take() (*model.Users, error)
	Last() (*model.Users, error)
	Find() ([]*model.Users, error)
	FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Users, err error)
	FindInBatches(result *[]*model.Users, batchSize int, fc func(tx gen.Dao, batch int) error) error
	Pluck(column field.Expr, dest interface{}) error
	Delete(...*model.Users) (info gen.ResultInfo, err error)
	Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
	UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
	Updates(value interface{}) (info gen.ResultInfo, err error)
	UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
	UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
	UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
	UpdateFrom(q gen.SubQuery) gen.Dao
	Attrs(attrs ...field.AssignExpr) IUsersDo
	Assign(attrs ...field.AssignExpr) IUsersDo
	Joins(fields ...field.RelationField) IUsersDo
	Preload(fields ...field.RelationField) IUsersDo
	FirstOrInit() (*model.Users, error)
	FirstOrCreate() (*model.Users, error)
	FindByPage(offset int, limit int) (result []*model.Users, count int64, err error)
	ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
	Scan(result interface{}) (err error)
	Returning(value interface{}, columns ...string) IUsersDo
	UnderlyingDB() *gorm.DB
	schema.Tabler
}

type PageinateInterface interface {
	Count() (count int64, err error)
}

type CommonDo struct {
	IDo
}

var Common CommonDo

func NewDo(dao IDo) CommonDo {
	Common.IDo = dao
	return Common
}

func PaginateCondition(pageSize int, page int) func(dao gen.Dao) gen.Dao {
	return func(dao gen.Dao) gen.Dao {

		if page <= 0 {
			page = 1
		}

		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}

		offset := (page - 1) * pageSize
		return dao.Offset(offset).Limit(pageSize)
	}
}
func PaginateNewCondition(pageSize int, page int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {

		if page <= 0 {
			page = 1
		}

		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}

		offset := (page - 1) * pageSize
		return db.Limit(pageSize).Offset(offset)
	}
}
func (c CommonDo) Paginate(ctx *fiber.Ctx) fiber.Map {
	page := ctx.Query("page", "1")
	pagesize := ctx.Query("pagesize", "10")
	fmt.Println("page:"+page, "pagesize:"+pagesize)
	total, _ := c.Count()
	// 每页数量和当前页
	//pageSize := 2
	currentPage, _ := strconv.Atoi(page)
	pageSize, _ := strconv.Atoi(pagesize)
	totalPages := (total + int64(pageSize) - 1) / int64(pageSize)

	fmt.Println("count----" + strconv.Itoa(int(total)))
	results, _ := c.Scopes(PaginateCondition(pageSize, currentPage)).Find()
	fmt.Println(pageSize, currentPage, totalPages, results)
	return fiber.Map{"pageSize": pageSize, "currentPage": currentPage, "totalPages": totalPages, "results": results}
}

// 分页泛型封装
func Page[T any](m T, ctx *fiber.Ctx, scopes ...func(db *gorm.DB) *gorm.DB) (fiber.Map, error) {
	//file, err := os.OpenFile("filePath.log", os.O_RDWR|os.O_CREATE, 0644)
	//log.SetOutput(file)
	page := ctx.Query("page", "1")
	pagesize := ctx.Query("pagesize", "10")
	currentPage, err := strconv.Atoi(page)
	if err != nil {
		log.Info("参数无效")
		return nil, fiber.ErrBadRequest
	}
	pageSize, err := strconv.Atoi(pagesize)
	if err != nil {
		log.Info("参数无效")
		return nil, fiber.ErrBadRequest
	}
	var total int64
	vars.DB.Model(m).Scopes(scopes...).Count(&total)

	log.Info("page:"+page, "pagesize:"+pagesize)
	totalPages := (total + int64(pageSize) - 1) / int64(pageSize)

	fmt.Println("count----" + strconv.Itoa(int(total)))
	scopes = append(scopes, PaginateNewCondition(pageSize, currentPage))

	var ms []T
	vars.DB.Scopes(scopes...).Find(&ms)
	fmt.Println(pageSize, currentPage, totalPages, ms)
	return fiber.Map{"pageSize": pageSize, "currentPage": currentPage, "totalPages": totalPages, "results": ms}, nil

}
